package hlm.server;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class MyServer {
    private final static int HTTP_PORT = 80;
    private final static int CODE_OK = 200;
    private final static int CODE_NOT_FOUND = 404;
    private final static int CODE_CREATE=201;
    private final static String OK = "OK";
    private final static String NOT_FOUND = "Not Found";
    private final static String CREATE = "Created";

    private final static String TYPE_PNG="Content-Type: image/png";
    private final static String TYPE_JPEG="Content-Type: image/jpeg";
    private final static String TYPE_DOC="Content-Type: application/msword";
    private final static String TYPE_HTML="Content-Type: text/html";
    private final static String TYPE_TXT="Content-Type: text/plain";

    private final static String SERVER_PATH = "C:\\Users\\HLM\\IdeaProjects\\HLMWorkspace\\myserver\\";
    private int port;
    private ServerSocket serverSocket;

    public MyServer() throws IOException {
        this.port = HTTP_PORT;
        serverSocket = new ServerSocket(HTTP_PORT);
    }

    public MyServer(int port) throws IOException {
        this.port = port;
        serverSocket = new ServerSocket(port);
    }

    public void listen() {
        while (true) {
            BufferedReader requestReader = null;
            OutputStream response = null;
            InputStream request = null;
            Socket client;
            try {
                client = serverSocket.accept();
                if (client == null) continue;
                System.out.println("客户端 " + client.getInetAddress().toString() + " 已连接");
                request = client.getInputStream();
                response = client.getOutputStream();
                byte[] datas =new byte[request.available()];
                int length=request.read(datas,0,datas.length);
                String requestInfo = new String(datas,0,length);
                System.out.print(requestInfo.toString());
                System.out.println("---->>>>>>>>>>>>>");
                if(requestInfo.equals(" ")|| requestInfo==null||requestInfo.equals("")){
                    continue;
                }
                Method method = getMethod(requestInfo);
                if(method == null){
                    continue;
                }
                switch (method) {  // 处理常见的几种请求
                    case GET:
                        handleGet(requestInfo, response);
                        break;
                    case POST:
                        handlePost(requestInfo,response);
                        break;
                    case PUT:
                        System.out.println("收到一个PUT请求，已忽略");
                        break;
                    case DELETE:
                        System.out.println("收到一个DELETE请求，已忽略");
                        break;
                    default:
                        break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {

                try {
                    request.close();
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("关闭失败");
                }
            }
        }
    }

    /**
     * @param firstLine GET /test.jpg HTTP/1.1
     * @param out outputStream
     */
    public void handleGet(String firstLine, OutputStream out){
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>");
        StringBuilder responseHeader = new StringBuilder("HTTP/1.1 ");
        FileInputStream fileResponse = null;
        byte[] data = null;
        try {
            String path = firstLine.substring(firstLine.indexOf('/') + 1, firstLine.indexOf(" HTTP/")).trim(); //  GET /test.txt HTTP/1.1
            if("".equals(path.trim())) path = "index.html"; //  / -> /index.html
            String fullPath = SERVER_PATH + path;
            System.out.println(fullPath);
            String fileFormate = path.substring(path.lastIndexOf('.') + 1); // test.jpg -> jpg
            File file = new File(fullPath);
            if (!file.exists() || file.isDirectory()) {
                //HTTP/1.1 404 NOT FOUND
                responseHeader.append(CODE_NOT_FOUND).append(" ").append(NOT_FOUND).append(System.lineSeparator());
            }else {
                responseHeader.append(CODE_OK).append(" ").append(OK).append(System.lineSeparator());
                //判断文件类型，添加适当内容
                if (fileFormate.equalsIgnoreCase("png")) {
                    responseHeader.append(TYPE_PNG).append(System.lineSeparator());
                } else if (fileFormate.equalsIgnoreCase("jpg") || fileFormate.equalsIgnoreCase("jpeg")) {
                    responseHeader.append(TYPE_JPEG).append(System.lineSeparator());
                } else if (fileFormate.equalsIgnoreCase("doc") || fileFormate.equalsIgnoreCase("docx")) {
                    responseHeader.append(TYPE_DOC).append(System.lineSeparator());
                } else if (fileFormate.equalsIgnoreCase("htm") || fileFormate.equalsIgnoreCase("html")) {
                    responseHeader.append(TYPE_HTML).append(System.lineSeparator());
                } else if (fileFormate.equalsIgnoreCase("txt")) {
                    responseHeader.append(TYPE_TXT).append(System.lineSeparator());
                }
                //响应日期
                responseHeader.append("Date: ").append(new Date()).append(System.lineSeparator());
                //添加文件长度
                responseHeader.append("Content-Length: ").append(file.length()).append(System.lineSeparator());
                responseHeader.append(System.lineSeparator());
                out.flush();
                //写入文件
                fileResponse = new FileInputStream(file);
                data = new byte[fileResponse.available()];
                System.out.println("Read length--> "+fileResponse.read(data));
            }
        } catch (IOException e) {
            e.printStackTrace();
            responseHeader.append(CODE_NOT_FOUND).append(" ").append(NOT_FOUND).append(System.lineSeparator());
            responseHeader.append(System.lineSeparator());
        } finally {
            try {
                out.write(responseHeader.toString().getBytes());
                if(data!=null){
                    out.write(data);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("关闭失败");
            }
            System.out.print(responseHeader.toString());
            System.out.println(new String(data));
            System.out.println("<<<<<<<<<<<<<<<<<<<<");
        }
    }
    public void handlePost(String request ,OutputStream out){
        String queryStr=null;
        Map<String,String> parameterMap = new HashMap<String, String>();
        String filename;
        final String BLANK=" ";
        final String CRLF="\r\n";
        String uri = request.substring(request.indexOf("/")+1,request.indexOf("HTTP/")).trim();
        System.out.println(uri);
        String bodyQueryStr = request.substring(request.lastIndexOf(CRLF)).trim();
        String [] keyValues =bodyQueryStr.split("&");
        for(String query:keyValues) {
            String[] kv=null;
            kv = query.split("=");
            kv = Arrays.copyOf(kv, 2);
            if (kv[1] == null) kv[1] = "";
            if (kv[0] == null) kv[0] = "";
            String key = kv[0];
            String value = kv[1];
            System.out.println(key + "--->" + value);
            if (!parameterMap.containsKey(key)) {
                parameterMap.put(key, value);
            }
        }
            StringBuilder responseHeader =new StringBuilder();
            StringBuilder responseBody = new StringBuilder();
        responseBody.append("<html>");
        responseBody.append("<head>");
        responseBody.append("<title>").append("服务器响应成功").append("</title>");
        responseBody.append("</head>");
        responseBody.append("<body>");
        responseBody.append("<h1>").append("登录成功,"+parameterMap.get("username")+"欢迎回来").append("</h1>");
        responseBody.append("</body>");
        responseBody.append("</html>");
            int code=0 ;
            responseHeader.append("HTTP/1.1").append(BLANK);
            responseHeader.append(code).append(BLANK);
            switch (code){
                case 200:
                    responseHeader.append("OK").append(CRLF);
                    break;
                case 404:
                    responseHeader.append("NOT FOUND").append(CRLF);
                    break;
                case 505:
                    responseHeader.append("SERVER ERROR").append(CRLF);
                    break;
            }
        responseHeader.append("Date").append(new Date()).append(CRLF);
        responseHeader.append("Server:").append("hlm Server/0.0.1;charset=utf-8").append(CRLF);
        responseHeader.append("Content-type:text/html;charset=utf-8").append(CRLF);
        responseHeader.append("Content-length:").append(responseBody.toString().getBytes().length).append(CRLF);
        responseHeader.append(CRLF);
        String responseto = responseHeader.toString()+responseBody.toString();
        System.out.println("-----以下");
        System.out.println(responseto);
            try {
                out.write(responseto.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    /**
     * 获取请求方法
     * GET / HTTP/1.1   method path protocol_version
     *
     * @param firstLine HTTP 请求的首行
     * @return Method
     */
    private Method getMethod(String firstLine)  {
        if(firstLine == null) return null;
        String method = firstLine.substring(0, firstLine.indexOf("/")).trim(); // -》 GET
        if ("get".equalsIgnoreCase(method)) return Method.GET;
        else if ("post".equalsIgnoreCase(method)) return Method.POST;
        else if ("put".equalsIgnoreCase(method)) return Method.PUT;
        else if ("delete".equalsIgnoreCase(method)) return Method.DELETE;
        else try {
                method=null;
                throw new Exception("不支持的方法 " + method);
            } catch (Exception e) {
                e.printStackTrace();
            }
        return null;
    }

    /**
     * 将 BufferedReader 转换成 String
     * @param reader origin reader
     * @return reader content
     * @throws IOException when reader is unreadable
     */
    private String bufferedReader2String(BufferedReader reader) throws IOException {
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line).append(System.lineSeparator());
        }
        reader.reset();  //重置指针
        return sb.toString();
    }

    public static void main(String[] args) throws IOException {
        MyServer myServer = new MyServer();
        myServer.listen();
    }
}


enum Method {
    GET,
    PUT,
    POST,
    DELETE
}